package minuy.android.minuygradienter;

import androidx.appcompat.app.AppCompatActivity;

import android.hardware.GeomagneticField;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.ThemedSpinnerAdapter;
import android.widget.Toast;

import minuy.android.minuygradienter.View.GradienterView;
import minuy.android.minuygradienter.View.LedMpu6050View;

//参考：https://blog.csdn.net/canney_chen/article/details/54693563
public class MainActivity extends AppCompatActivity implements SensorEventListener {

    final String TAG = "主界面";

    //传感器管理器
    private SensorManager sensorManager;
    //加速度传感器
    private Sensor acc_sensor;
    //磁场传感器
    private Sensor mag_sensor;

    //加速度传感器原始数据
    private float[] accValues = new float[3];
    //磁场传感器原始数据
    private float[] magValues = new float[3];
    // 旋转矩阵，用来保存磁场和加速度的数据
    private float r[] = new float[9];
    // 模拟方向传感器的数据（原始数据为弧度）
    private float values[] = new float[3];

    //上部分的控件
    private GradienterView gradienterView;
    //下部分小灯模拟控件（算法在这里面，重点）
    private LedMpu6050View ledMpu6050View;
    //水平数值显示文本控件
    private TextView tvHorz;
    //垂直数值显示文本控件
    private TextView tvVert;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //设置界面标题
        setTitle("摇动 观察 小灯！");

        //初始化视图
        gradienterView = (GradienterView)findViewById(R.id.gv_hv);
        ledMpu6050View = findViewById(R.id.lmv_main);

        //获取文本控件
        tvVert = (TextView)findViewById(R.id.tvv_vertical);
        tvHorz = (TextView)findViewById(R.id.tvv_horz);

        //获取传感器管理器
        sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

        //弹出提示
        Toast.makeText(getApplicationContext(),"摇动",Toast.LENGTH_SHORT).show();
        Toast.makeText(getApplicationContext(),"观察",Toast.LENGTH_SHORT).show();
        Toast.makeText(getApplicationContext(),"小灯！",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onResume() {
        super.onResume();
        //获取加速度计实例
        acc_sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        //获取磁场传感器实例
        mag_sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

        // 给传感器注册监听：
        sensorManager.registerListener(this, acc_sensor, SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this, mag_sensor, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        // 取消传感器值变化的监听
        sensorManager.unregisterListener(this);
        super.onPause();
    }

    @Override
    protected void onStop() {
        // 取消传感器值变化的监听
        sensorManager.unregisterListener(this);
        super.onStop();
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        //Toast.makeText(getApplicationContext(),"传感器精度变化："+sensor.getName()+" 值："+accuracy,Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // 获取手机触发event的传感器的类型
        int sensorType = event.sensor.getType();

        switch (sensorType) {
            case Sensor.TYPE_ACCELEROMETER://加速度传感器
                //保存数值
                accValues = event.values.clone();
                break;
            case Sensor.TYPE_MAGNETIC_FIELD://磁场传感器
                //保存数值
                magValues = event.values.clone();
                break;
        }

        //测试用，测试不用磁场传感器的效果（改为true）
        if(false){
            //获取旋转矩阵
            getRotationMatrix(r, accValues);
            //根据旋转矩阵获取角度
            getOrientation(r, values);
        }else{
            //获取旋转矩阵
            SensorManager.getRotationMatrix(r,null,accValues,magValues);
            //根据旋转矩阵获取角度
            SensorManager.getOrientation(r,values);
        }

        // 获取　沿着Z轴转过的角度
        float azimuth = values[0];

        // 获取　沿着X轴倾斜时　与Y轴的夹角
        float pitchAngle = values[1];

        // 获取　沿着Y轴的滚动时　与X轴的角度
        //此处与官方文档描述不一致，所在加了符号（https://developer.android.google.cn/reference/android/hardware/SensorManager.html#getOrientation(float[], float[])）
        float rollAngle = - values[2];

        //调整视图
        onAngleChanged(rollAngle, pitchAngle, azimuth);
    }

    /**
     * 计算得到姿态
     * @param R 旋转矩阵
     * @param values 之前的数据
     * @return 更新数据
     */
    public float[] getOrientation(float[] R, float[] values) {

        values[0] = (float) Math.atan2(R[1], R[4]);
        values[1] = (float) Math.asin(-R[7]);
        values[2] = (float) Math.atan2(-R[6], R[8]);

        return values;
    }

    /**
     * 得到旋转矩阵
     * @param R 旋转矩阵
     * @param gravity 加速度计
     * @return 成功/失败
     */
    public boolean getRotationMatrix(float[] R,float[] gravity) {
        float Ax = gravity[0];
        float Ay = gravity[1];
        float Az = gravity[2];

        final float normsqA = Ax * Ax + Ay * Ay + Az * Az;
        final float g = 9.81f;
        final float freeFallGravitySquared = 0.01f * g * g;
        if (normsqA < freeFallGravitySquared) {
            // 重力小于正常值的10%
            return false;
        }

        float Hx =  Az - Ay;
        float Hy =  Ax - Az;
        float Hz =  Ay - Ax;
        final float normH = (float) Math.pow(Hx * Hx + Hy * Hy + Hz * Hz,0.5);

        if (normH < 0.1f) {
            // 设备接近自由落体（还是在太空？）或者靠近磁极。典型值大于100。
            return false;
        }

        final float invH = 1.0f / normH;
        Hx *= invH;
        Hy *= invH;
        Hz *= invH;
        final float invA = 1.0f / (float) Math.sqrt(normsqA);
        Ax *= invA;
        Ay *= invA;
        Az *= invA;
        final float Mx = Ay * Hz - Az * Hy;
        final float My = Az * Hx - Ax * Hz;
        final float Mz = Ax * Hy - Ay * Hx;

        //R
        R[0] = Hx;     R[1] = Hy;     R[2] = Hz;
        R[3] = Mx;     R[4] = My;     R[5] = Mz;
        R[6] = Ax;     R[7] = Ay;     R[8] = Az;

        return true;
    }


    /**
     * 角度变更后显示到界面
     * @param rollAngle
     * @param pitchAngle
     * @param azimuth
     */
    private void onAngleChanged(float rollAngle, float pitchAngle, float azimuth){
        //上半部分设置
        gradienterView.setAngle(rollAngle, pitchAngle,azimuth);
        //传值到小灯模拟
        ledMpu6050View.setAngle(rollAngle, pitchAngle,azimuth);

        //设置值显示
        tvHorz.setText((int)Math.toDegrees(rollAngle) + "°");
        tvVert.setText((int)Math.toDegrees(pitchAngle) + "°");
    }
}